package model;

import java.io.Serializable;
import java.util.ArrayList; 
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.*;

import processObjects.ValoracionJugadorList;
import processObjects.ValoracionJugadorObject;
import viewObjects.CategoriaVO;
import model.Equipo;

@Entity
@Table(name = "Categorias")
public class Categoria {

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private int id;

	private Date fechaInicio;
	private char nivel;
	private String descripcion;
	@Embedded
	private Fixture fixture;
	@Transient
	private ArrayList<Equipo> equiposParticipantes;
	@Transient
	private ArrayList<Equipo> equiposNoParticipantes;
	@OneToMany
	@JoinColumn(name="idCategoria")
	private List<Posicion> posiciones;
	
	public Categoria(){
		equiposParticipantes = new ArrayList<Equipo>();
		equiposNoParticipantes = new ArrayList<Equipo>();
		posiciones = new ArrayList<Posicion>();
	}
	
	//En base a categoria existente
	public Categoria(Categoria categoria, Date fechaInicio){
		this.descripcion = categoria.getDescripcion();
		this.nivel = categoria.getNivel();
		this.fechaInicio = fechaInicio;
		
		equiposParticipantes = new ArrayList<Equipo>();
		equiposNoParticipantes = new ArrayList<Equipo>();
		posiciones = new ArrayList<Posicion>();
		
		//copio los equipos
		for(Equipo equipo : categoria.equiposNoParticipantes){
			this.equiposNoParticipantes.add(equipo);
		}
		for(Equipo equipo : categoria.equiposParticipantes){
			this.equiposParticipantes.add(equipo);
		}	
	}
	
	public Categoria(Date fechaInicio, String descripcion, char nivel,
			Fixture fixture) {
		this.fechaInicio = fechaInicio;
		this.descripcion = descripcion;
		this.nivel = nivel;		
		this.fixture = fixture;
		
		equiposParticipantes = new ArrayList<Equipo>();
		equiposNoParticipantes = new ArrayList<Equipo>();
		posiciones = new ArrayList<Posicion>();
	}

	public ArrayList<Equipo> getEquiposParticipantes() {
		return equiposParticipantes;
	}

	public void addEquipoParticipante(Equipo equipoParticipante) {
		this.equiposParticipantes.add(equipoParticipante);
	}
	
	public void addEquiposParticipantes(ArrayList<Equipo> equiposParticipantes) {
		this.equiposParticipantes.addAll(equiposParticipantes);
	}

	public ArrayList<Equipo> getEquiposNoParticipantes() {
		return equiposNoParticipantes;
	}

	public void addEquipoNoParticipante(Equipo equipoNoParticipante) {
		this.equiposNoParticipantes.add(equipoNoParticipante);
	}
	
	public void addEquiposNoParticipantes(ArrayList<Equipo> equiposNoParticipantes) {
		this.equiposNoParticipantes.addAll(equiposNoParticipantes);
	}

	public ArrayList<Equipo> getEquipos(){
		ArrayList<Equipo> equipos = new ArrayList<Equipo>();
		for (Equipo e : this.getEquiposNoParticipantes()){
			equipos.add(e);
		}
		for (Equipo e : this.getEquiposParticipantes()){
			equipos.add(e);
		}
		
		return equipos;
	}
	
	public Date getFechaInicio() {
		return fechaInicio;
	}

	public void setFechaInicio(Date fechaInicio) {
		this.fechaInicio = fechaInicio;
	}

	public String getDescripcion() {
		return descripcion;
	}

	public void setDescripcion(String descripcion) {
		this.descripcion = descripcion;
	}

	public char getNivel() {
		return nivel;
	}

	public void setNivel(char nivel) {
		this.nivel = nivel;
	}

	public Fixture getFixture() {
		return fixture;
	}

	public void setFixture(Fixture fixture) {
		this.fixture = fixture;
	}

	public List<Posicion> getPosiciones() {
		return posiciones;
	}

	public void addPosicion(Posicion posicion) {
		this.posiciones.add(posicion);
	}
	
	public void addPosiciones(ArrayList<Posicion> posiciones) {
		this.posiciones.addAll(posiciones);
	}	
	
	public CategoriaVO getMinimalView(){
		CategoriaVO cV = new CategoriaVO(this.id, this.fechaInicio, this.descripcion,this.nivel);
		return cV;
	}
	
	public ArrayList<Equipo> getAscensosRemove(int cantidad){
		ArrayList<Equipo> ascensos = new ArrayList<Equipo>();		
		//busco los "cantidad" mayores promedio
		while(ascensos.size() < cantidad){
			Equipo equipoActual = null;
			float mayorPromedio = -1;
			
			for (Equipo equipo : this.equiposParticipantes){
				if (equipo.getPromedio() > mayorPromedio){
					mayorPromedio = equipo.getPromedio();
					equipoActual = equipo;
				}else if (equipo.getPromedio() == mayorPromedio){
					//En caso de ser iguales se define por el que tiene
					//mas antiguedad en la liga
					if (equipo.getFechaAlta().compareTo(equipoActual.getFechaAlta()) > 0){
						mayorPromedio = equipo.getPromedio();
						equipoActual = equipo;
					}
				}
			}
			
			if (equipoActual != null){
				equipoActual.setPromedio(0);
				ascensos.add(equipoActual);
				this.equiposParticipantes.remove(equipoActual);
			}
		}
		
		return ascensos;
	}
	
	public ArrayList<Equipo> getDescensosRemove(int cantidad){
		ArrayList<Equipo> descensos = new ArrayList<Equipo>();		
		//busco los "cantidad" menores promedio
		while(descensos.size() < cantidad){
			Equipo equipoActual = null;
			float menorPromedio = 99;
			
			for (Equipo equipo : this.equiposParticipantes){
				if (equipo.getPromedio() < menorPromedio){
					menorPromedio = equipo.getPromedio();
					equipoActual = equipo;
				}else if (equipo.getPromedio() == menorPromedio){
					//En caso de ser iguales se define por el que tiene
					//mas antiguedad en la liga
					if (equipo.getFechaAlta().compareTo(equipoActual.getFechaAlta()) < 0){
						menorPromedio = equipo.getPromedio();
						equipoActual = equipo;
					}
				}
			}
			
			if (equipoActual != null){
				equipoActual.setPromedio(0);
				descensos.add(equipoActual);
				this.equiposParticipantes.remove(equipoActual);
			}
		}
		
		return descensos;
	}

	public ArrayList<Equipo> getMantienenRemove(){
		ArrayList<Equipo> restoEquipos = this.getEquipos();
		this.equiposNoParticipantes.clear();
		this.equiposParticipantes.clear();
		return restoEquipos;
	}
	
	public ArrayList<Jugador> getMejoresJugadoresPorPosicion(String posicion, int cantidad){
		ArrayList<Jugador> jugadores = new ArrayList<Jugador>();
		ValoracionJugadorList valoraciones = new ValoracionJugadorList();
		
		for(Fecha fecha : this.fixture.getFechasRegulares()){
			for(Partido partido : fecha.getPartidos()){
				for(Estadistica estadistica : partido.getEstadisticas()){
					if (estadistica.getJugador().getPosicion().equals(posicion)){
						if (posicion.equals(constants.Posicion.ALERO)){
							//(Cant puntos . 2) + (Cant robos . 1)
							int puntos = 2*estadistica.getPuntos();
							int robos = estadistica.getRobos();
							valoraciones.addValoracion(new ValoracionJugadorObject(estadistica.getJugador(), puntos + robos));
						}else if (posicion.equals(constants.Posicion.BASE)){
							//(Cant de Asistencias . 3) + (Cant robos . 2) + (Cant puntos . 1)
							int asistencias = 3*estadistica.getAsistencias();
							int puntos = estadistica.getPuntos();
							int robos = 2*estadistica.getRobos();
							valoraciones.addValoracion(new ValoracionJugadorObject(estadistica.getJugador(), puntos + robos + asistencias));
						}else if (posicion.equals(constants.Posicion.PIVOT)){
							//(cant de rebotes .3) + (cant puntos.2)   + (cant de tapas .1)
							int rebotes = 3*(estadistica.getRebotesAtaque() * estadistica.getRebotesDefensa());
							int puntos = 2*(estadistica.getPuntos());
							int tapas = estadistica.getTapas();
							valoraciones.addValoracion(new ValoracionJugadorObject(estadistica.getJugador(), puntos + rebotes + tapas));
						}
					}
				}
			}
		}
		
		//tengo todas las valoraciones cargadas de la posicion pasada como parametro
		
		while(jugadores.size() < cantidad){
			ValoracionJugadorObject valoracionActual = null;
			int mayorValoracion = 0;
			
			for (ValoracionJugadorObject valoracion : valoraciones.getValoraciones()){
				if (valoracion.getValoracion() > mayorValoracion){
					mayorValoracion = valoracion.getValoracion();
					valoracionActual = valoracion;
				}
			}
			
			if (valoracionActual != null){
				jugadores.add(valoracionActual.getJugador());
				valoraciones.getValoraciones().remove(valoracionActual);
			}
		}
		
		return jugadores;
	}

	public void generarFixtureNuevaCategoria(ArrayList<Equipo> equipos) {
		this.fixture = new Fixture(equipos, this.fechaInicio);
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public void setPosicionesIniciales(ArrayList<Equipo> equipos) {
		this.posiciones = new ArrayList<Posicion>();
		for(Equipo e : equipos){
			Posicion p = new Posicion(e, this);
			this.posiciones.add(p);
		}
		
		
	}

}
